/**
  Copyright (c) 2009 ATTi 
  All rights reserved.
  Author: Michael Shu
  Date: 12/28/2009
*/
@isTest
private class SendEmailControllerTester {
  private static Case curCase;
  private static Account csAccount;
  private static Contact csContact;
  private static SendEmailController controller;
  private static PageReference nextPage;
  private static User testUser;
  private static EmailMessage email;
  
  private static string getQueryString(String objName, String whereClause){
    Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe(); 
    Schema.SObjectType obj = gd.get(objName) ;
    Map<String, Schema.SObjectField> M = obj.getDescribe().fields.getMap() ;
      String objFields = '';
      for (Schema.SObjectField field : M.values()){
      String fieldname = field.getDescribe().getName();
      objFields += fieldname + ',';
      if(fieldname != 'Id' && fieldname.endsWith('Id') && fieldname != 'ParentId'){
        fieldname = fieldname.substring(0,fieldname.lastIndexOf('Id')) + '.Name'; // eg. ContactId -> Contact.Name 
        objFields += fieldname + ',';
      }
    }  
    objFields = objFields.substring(0, objFields.lastIndexOf(',')); //trim last comma;
    String qryString = ' select ' + objFields + ' from ' + objName + ' ' + whereClause + ' limit 1';
    System.debug('test qryStringe = ' + qryString);
    return qryString;          
  }
  
  private static void testInit() {
    User u_new = new User();
    u_new.UserName = 'xyz_1234567890@abcd.com';
    u_new.LastName = 'Michael Shu Test Email';
    u_new.Email = 'xyz_1234567890@atti.com';
    u_new.Alias = 'abcde';
    u_new.CommunityNickname = 'xyaz_1234556';
    u_new.TimeZoneSidKey = 'America/Los_Angeles';
    u_new.LocaleSidKey = 'en_US';
    u_new.EmailEncodingKey = 'UTF-8';
    u_new.ProfileId = [select ID from Profile where Name =: 'System Administrator' limit 1].Id;
    u_new.UserRoleId = [select ID from UserRole where Name =: 'Information Systems' limit 1].Id;
    u_new.LanguageLocaleKey = 'en_US';
    insert u_new;
    testUser = [select FirstName from User where UserName = 'xyz_1234567890@abcd.com' limit 1];
    
    Lead newLead = new Lead();
    newLead.Phone = '9999999999';
    newLead.LastName = 'shu';
    newLead.Company = 'test_account_case_email_1222';
    System.runAs(testUser){
      insert newLead;
    }
    System.runAs(testUser){  
      Database.LeadConvert lc = new database.LeadConvert();
      lc.setLeadId(newLead.id);
      LeadStatus convertStatus = [Select Id, MasterLabel from LeadStatus where IsConverted=true limit 1];
      lc.setConvertedStatus(convertStatus.MasterLabel);
      Database.LeadConvertResult lcr = Database.convertLead(lc);
      System.assert(lcr.isSuccess());
    }    
    String whereClause = ' where Name = \'' + newLead.Company + '\'';
    String qryString = getQueryString('Account', whereClause);
    csAccount = Database.query(qryString);
    
    Contact newContact = new Contact(AccountId = csAccount.Id, LastName = 'test_contact_case_email', FirstName = 'send email', Email = 'contact@testsanebox.com', Ingenio_UserID__c = GetUniqueIngenioUserID());
    System.runAs(testUser){
      insert newContact;
    }
    whereClause = ' where LastName = \'' + newContact.LastName + '\'';
    qryString = getQueryString('Contact', whereClause);             
    csContact = Database.query(qryString);
    
    String csSubject = 'testSubject';
    String csWebEmail = 'email@testsandbox.com';
    String csDescription = 'This is for test only';
    Case newCase = new Case(subject = csSubject, SuppliedEmail = csWebEmail, description = csDescription, AccountId = csAccount.Id, ContactId = csContact.Id);
    System.runAs(testUser){
      insert newCase;
    }
    
    whereClause = ' where AccountId = \'' + csAccount.Id + '\' and ContactId = \'' + csContact.Id + '\'';
    qryString = getQueryString('Case', whereClause); 
    curCase = Database.query(qryString);
    
    EmailMessage e = new EmailMessage();
    e.Incoming = true;
    e.ParentId = curCase.Id;
    e.Subject = 'Test email';
    e.FromAddress = 'test_from@atti-null.com';
    e.ToAddress = 'test_to@atti-null.com';
    Database.Saveresult e_rt;
    System.runAs(testUser){
      e_rt = Database.insert(e);
    }              
    email = [select Id, Subject, FromAddress, ToAddress from EmailMessage where Id =: e_rt.getId() limit 1];
  }
  
  public static testMethod void testSendEmail() {
    testInit();
    System.runAs(testUser){
      PageReference pageRef = Page.SendAnEmailPage;
      Test.setCurrentPage(pageRef);
      controller = new SendEmailController();
      nextPage = controller.init();
      System.assertEquals('/500/o', nextPage.getUrl());  
      // cancel send email    
      ApexPages.currentPage().getParameters().put('id', curCase.Id);  
      ApexPages.currentPage().getHeaders().put('Host', 'c.cs1.visual.force.com');
      controller = new SendEmailController();
      controller.init();
      nextPage = controller.cancel();
      System.assertEquals('/' + curCase.Id, nextPage.getUrl());  
      // send email
      controller = new SendEmailController();
      controller.init();
      nextPage = controller.send();
      System.assertEquals('/' + curCase.Id, nextPage.getUrl());  
      // spell check(null)
      controller = new SendEmailController();
      controller.init();
      nextPage = controller.checkSpelling();
      System.assertEquals(null, nextPage);  
    }        
  }

  public static testMethod void testAttachmentInEmail() {
    testInit();
      PageReference pageRef = Page.SendAnEmailPage;
      Test.setCurrentPage(pageRef);
      // add attachment from Local driver    
      ApexPages.currentPage().getParameters().put('id', curCase.Id);  
      ApexPages.currentPage().getHeaders().put('Host', 'c.cs1.visual.force.com');
      controller = new SendEmailController();
      System.runAs(testUser){
        controller.init();
      }
      System.assertEquals(true,  controller.getIsAttEmpty());
      System.assertEquals(false, controller.getIsAttNotEmpty());
      String fName = 'AttachmentTest';
      Blob fBody = Blob.valueOf('This is a Test');
      Integer fSize = 120000;
      controller.fileName = fName;
      controller.theBlob = fBody;
      controller.fileSize = fSize;
      System.runAs(testUser){
        nextPage = controller.addAttchment();
      }
      System.assertEquals(false, controller.getIsAttEmpty());
      System.assertEquals(true,  controller.getIsAttNotEmpty());
      System.assertEquals(1, controller.lAtt.size());
      System.assertEquals(fName, controller.lAtt[0].fileName);
      System.assertEquals(fSize, controller.lAtt[0].fileSize);
      // add attachment from the existing attachment assoiciated in the same case
      fName = 'Insert existing Attachment for test';
      fBody = Blob.valueOf('This is a Inserted existing attachment for test');    
        Attachment oneAttachment = new Attachment(Name = fName, Body = fBody, ParentId = curCase.Id);
        System.runAs(testUser){
          insert oneAttachment;
        }
        Attachment attachment_rst = [select Id from Attachment a where a.Name =: fName limit 1];  
        controller.attachment_id = attachment_rst.Id;
        nextPage = controller.addAttchment();
      System.assertEquals(2, controller.lAtt.size());
      System.assertEquals(fName, controller.lAtt[1].fileName);
      // remove attachment
      controller.lAtt[0].istoDel = true; // delete the 1st attachment
      nextPage = controller.removeAttchment();  
      System.assertEquals(1, controller.lAtt.size());
      System.assertEquals(fName, controller.lAtt[0].fileName);
      // add one attachment again
      fName = 'Add one Attachment for Test again';
      fBody = Blob.valueOf('This is a 3rd time to add attachment');
      fSize = 10000;
      controller.fileName = fName;
      controller.theBlob = fBody;
      controller.fileSize = fSize;
      System.runAs(testUser){
        nextPage = controller.addAttchment();
      }
      System.assertEquals(2, controller.lAtt.size());
      System.assertEquals(fName, controller.lAtt[1].fileName);
      System.assertEquals(fSize, controller.lAtt[1].fileSize);  
      // de-select all/select all
      System.assertEquals(true, controller.lAtt[0].istoSel);
      System.assertEquals(true, controller.lAtt[1].istoSel);
      controller.selectAll();
      System.assertEquals(false, controller.lAtt[0].istoSel);
      System.assertEquals(false, controller.lAtt[1].istoSel);
      controller.selectAll();
      System.assertEquals(true, controller.lAtt[0].istoSel);
      System.assertEquals(true, controller.lAtt[1].istoSel);
        
      // send email with the attachment
      System.runAs(testUser){
        nextPage = controller.send();
      }
      System.assertNotEquals(null, nextPage, ApexPages.getMessages());
      System.assertEquals('/' + curCase.Id, nextPage.getUrl());         
  }
  
  public static testMethod void testEmailTemplate() {
    testInit();
    PageReference pageRef = Page.SendAnEmailPage;
    Test.setCurrentPage(pageRef);
    
    ApexPages.currentPage().getParameters().put('id', curCase.Id);  
    ApexPages.currentPage().getHeaders().put('Host', 'c.cs1.visual.force.com');
    controller = new SendEmailController();
    controller.init();  
    
    curCase.Subject = '';
    List<EmailTemplate> listEmailTemplate = new List<EmailTemplate>([select Id from EmailTemplate e 
                                                                     where IsActive = true and TemplateType = 'text'
                                                                           and (folder.name = 'Customer Care - IR' or folder.name = 'Customer Care Templates')
                                                                     limit 1]);
    Integer i = 0;
    for(EmailTemplate eTemplate : listEmailTemplate){
      controller.template_id = eTemplate.Id;  
        Messaging.SingleEmailMessage nEmail;
        nEmail = new Messaging.SingleEmailMessage();
      nEmail.setWhatId(curCase.Id);
      nEmail.setTargetObjectId(csContact.Id); 
      nEmail.setTemplateId(controller.template_id);
      Messaging.SingleEmailMessage[] lmail_temp = new Messaging.SingleEmailMessage[]{nEmail};
      try{
        Messaging.sendEmail(lmail_temp);
      }catch(Exception ex){
        System.debug('Test Email error ' + ex);
      }
      String parsedBody = nEmail.getPlainTextBody();
      String parsedSubject = nEmail.getSubject();
      
      controller.refreshBody();
      //System.assertEquals(parsedSubject, controller.subject);  
      //System.assertEquals(parsedBody, controller.body, ' eTemplate.Id[' + i + ']is ' + eTemplate.Id);
      i++;
    }
  }
    
  public static testMethod void testEmailErrorMessage() {
    testInit();
    PageReference pageRef = Page.SendAnEmailPage;
    Test.setCurrentPage(pageRef);
    
    ApexPages.currentPage().getParameters().put('id', curCase.Id);  
    ApexPages.currentPage().getHeaders().put('Host', 'c.cs1.visual.force.com');
    
    controller = new SendEmailController();
    controller.init();    
    controller.toContactName = '';
    controller.additionalTo = '';
    controller.bcc = '';
    controller.cc = '';
    controller.subject = '';
    controller.body = '';
    controller.send();
    List<ApexPages.Message> messages = ApexPages.getMessages();  
    for(ApexPages.Message m : messages){
      System.debug('error message : ' + m.getSummary());
    }
    System.assertEquals(2, messages.size());  
    System.assertEquals(SendEmailControllerMessage.Error_RequiredToemailMissing, messages[0].getSummary());
    System.assertEquals(SendEmailControllerMessage.Error_SubjectMissing, messages[1].getSummary());

    controller.additionalTo = '123@456.789'; // wrong email format
    controller.bcc = 'a@b.com1'; // wrong email format
    controller.cc = 'a@att.com.uk'; // correct email format
    controller.subject = 'Re:';    
    controller.send();
    messages = ApexPages.getMessages();  
    for(ApexPages.Message m : messages){
      System.debug('error message : ' + m.getSummary());
    }
    System.assertEquals(4, messages.size());
      
    System.assertEquals(SendEmailControllerMessage.Error_AdditionalToEmailFormatError, messages[2].getSummary()); //?how to clear ApexPages.Message
    System.assertEquals(SendEmailControllerMessage.Error_BCCEmailFormatError, messages[3].getSummary());
  }
  
  public static testMethod void testEmailbody(){
    testInit();
    PageReference pageRef = Page.SendAnEmailPage;
    Test.setCurrentPage(pageRef);
    
    ApexPages.currentPage().getParameters().put('id', curCase.Id);  
    ApexPages.currentPage().getHeaders().put('Host', 'c.cs1.visual.force.com');
    
    controller = new SendEmailController();
    controller.init();
    
    System.assertEquals(SendEmailControllerMessage.TextBodyType, controller.getbodyType());
    System.assertEquals(SendEmailControllerMessage.SwitchToHTML, controller.getSwitchToName());
    controller.setbodyType();
    System.assertEquals(SendEmailControllerMessage.HTMLBodyType, controller.getbodyType());
    System.assertEquals(SendEmailControllerMessage.SwitchToText, controller.getSwitchToName());
    
    System.assertEquals(SendEmailControllerMessage.Title, controller.getTitle());
  }
  
  public static testMethod void testContactSelection(){
    testInit();
    List<Contact> newContacts = new List<Contact>();
    Contact c_new = new Contact(LastName = 'test_contact_case_email', FirstName = 'send email'
                          , Email = 'contact@testsanebox.com', Ingenio_UserID__c = GetUniqueIngenioUserID());
    newContacts.add(c_new);
    for(Integer i=0; i < 10 ; i++){
      Contact c = new Contact(LastName = 'test_contact_case_email' + i, FirstName = 'send email'
                          , Email = 'contact' + i + '@testsanebox.com', Ingenio_UserID__c = GetUniqueIngenioUserID());
      newContacts.add(c);
    }
    System.runAs(testUser){
      insert newContacts;
    }
    List<Contact> curContacts = new List<Contact>([select Id, Email from Contact where LastName like 'test_contact_case_email%']);
    System.assertEquals(12, curContacts.size());
    
    PageReference pageRef = Page.SendAnEmailPage;
    Test.setCurrentPage(pageRef);
    
    ApexPages.currentPage().getParameters().put('id', curCase.Id);  
    ApexPages.currentPage().getHeaders().put('Host', 'c.cs1.visual.force.com');
    
    controller = new SendEmailController();
    System.runAs(testUser){
      controller.init();
      System.assertEquals('/' + curCase.Id, controller.send().getUrl());
    }
    controller = new SendEmailController();
    System.runAs(testUser){
      controller.init();
      controller.toContactName = 'send email test_contact_case_email' + 1;
      System.assertEquals('/' + curCase.Id, controller.send().getUrl());
    }

    controller = new SendEmailController();
    System.runAs(testUser){
      controller.init();
    }
    controller.toContactId = null;
    System.runAs(testUser){
      controller.send();
    }
    List<ApexPages.Message> messages = ApexPages.getMessages();  
    for(ApexPages.Message m : messages){
      System.debug('error message : ' + m.getSummary());
    }
    System.assertEquals(1, messages.size());
    System.assertEquals(SendEmailControllerMessage.Error_TooManyContactMatching, messages[0].getSummary());  

    Contact c_new_with_wrong_email = new Contact(LastName = 'test_contact_with_wrong_email', FirstName = ''
                          , Email = '123@456.789', Ingenio_UserID__c = GetUniqueIngenioUserID());
    System.runAs(testUser){
      insert c_new_with_wrong_email;
    }
    controller = new SendEmailController();
    System.runAs(testUser){
      controller.init();
    }
    controller.toContactName = 'test_contact_with_wrong_email';
    System.runAs(testUser){
      controller.send();  
    }
    messages = ApexPages.getMessages();  
    for(ApexPages.Message m : messages){
      System.debug('error message : ' + m.getSummary());
    }
    System.assertEquals(2, messages.size());
    System.assertEquals(SendEmailControllerMessage.Error_TooManyContactMatching, messages[0].getSummary());  
    System.assertEquals(SendEmailControllerMessage.Error_InvalidContactEmail, messages[1].getSummary());    
  }  
  
  public static testMethod void testReplyReplyToAllForward(){
    testInit();
    PageReference pageRef = Page.SendAnEmailPage;
    Test.setCurrentPage(pageRef);
    
    // reply
    ApexPages.currentPage().getParameters().put('id', curCase.Id);  
    ApexPages.currentPage().getHeaders().put('Host', 'c.cs1.visual.force.com');
    ApexPages.currentPage().getParameters().put('email_id', email.Id);    
    ApexPages.currentPage().getParameters().put('replyToAll', '0');  
    controller = new SendEmailController();
    controller.init();  
    controller.send();  
      
    // reply to All
    ApexPages.currentPage().getParameters().put('id', curCase.Id);  
    ApexPages.currentPage().getHeaders().put('Host', 'c.cs1.visual.force.com');
    ApexPages.currentPage().getParameters().put('email_id', email.Id);    
    ApexPages.currentPage().getParameters().put('replyToAll', '1');  
    controller = new SendEmailController();
    controller.init();
    controller.send();
    
    // forward
    ApexPages.currentPage().getParameters().put('id', curCase.Id);  
    ApexPages.currentPage().getHeaders().put('Host', 'c.cs1.visual.force.com');
    ApexPages.currentPage().getParameters().put('email_id', email.Id);    
    ApexPages.currentPage().getParameters().put('forward', '1');  
    controller = new SendEmailController();
    controller.init();
    controller.toEmail = 'test_forward@atti-null.com';
    controller.send();      
  }
  
  private static integer uniqueIngenioUserID = 909090000;
  private static string GetUniqueIngenioUserID()
  {
    return '' + (uniqueIngenioUserID++);  
  }
}